const {Student, StudentPosition, Frame} = require('./model.js');
const utils = require('./utils.js');
const {BuildingPosition, Building} = require("./model");
const {probability} = require("./utils");
let main = document.getElementById('main');
let context = main.getContext("2d");

// 初始化数据
const initData = {
    time: 0,    // 模拟时间
    timeShift: 4, // 时间转换 例 2：1s(真实时间) = 2h (模拟时间)
    nucleicAcid:{
        // 做核酸时的时间 ， 用于核酸结果的延迟发放
        day: -1,
        hour: -1,
        whetherNucleicAcid: true,  // 是否全员核酸(留给用户选择)
        isNucleicAcidNow: false,      // 现在是否在做核酸
        nucleicAcidSpacers: 4,  // 没隔几天做一轮核酸  day
        nucleicAcidResults: 6, // 做完核酸后核酸出结果的时间  hour
        isTheResultReleased: false, // 核酸结果是否已经发放，默认未false
    },
    studentLength: 10,   // 学生的数量
    day: 0,     // 天  系统模拟运行的天数
    hour: 0,    // 小时  系统模拟运行的小时数
    background: '#fafafa', // 背景颜色
    r: 10, // 圆的半径
    frameWidth: 6,  // 圆的宽度
    students: [],   // 学生数组
    noiseAmplitude: 1, // 噪音幅度
    probability: {       // 学生的患病概率是各项概率相加的结果
        asymptomaticProbability: 20, // 接触无症状感染者患病的概率
        wearAMaskProbability: -10, // 佩戴口罩时，学生与佩戴口罩者接触后的患病比例
        withoutAMaskProbability: 0, // 不佩戴口罩时，学生与不佩戴口罩者接触后的患病比例
        sickProbability: 60, // 健康学生与患病者接触后的患病比例
    },
    symptom: {       // 学生患病时，学生患病症状的概率
        illness: 60,    // 发病概率，另一种则为症状为40%
    },
    // 健康状态
    healthStatus: {
        data: ['health', 'asymptomatic', 'sick'],  // 健康状态数据
        health: 'rgb(255, 255, 255)',   // 健康时，代表学生圆对应的填充颜色
        asymptomatic: 'rgb(255, 235, 59)', // 无症状感染者，代表学生圆对应的填充颜色
        sick: 'rgb(244, 67, 54)', // 患病时，代表学生圆对应的填充颜色
    },
    // 是否佩戴口罩
    facialMask: {
        data: ['wearAMask', 'withoutAMask'],  // 是否佩戴口罩数据
        wearAMask: 'rgb(76, 175, 80)',  // 佩戴口罩时，代表学生的圆圈的颜色
        withoutAMask: 'rgb(186, 104, 200)', // 不佩戴口罩使，代表学生的圆圈的颜色
    },
    // 核算监测结果
    monitor: {
        data: ['negative', 'masculine', 'notDone'],  // 监测结果数据
        negative: 'rgb(33, 150, 243)', // 核算监测为阴性时，代表学生圆中的文字的颜色
        masculine: 'rgb(245, 124, 0)', // 核算监测为阳性时，代表学生圆中的文字的颜色
        notDone: 'rgb(50,50,50)', // 未做核算时，代表学生圆中的文字的颜色
    },
    buildingList: [],    // 建筑列表
    frame: null,
}
init();

// 初始化
function init() {
    // 初始化数据
    initData.time = 0;
    initData.students = [];
    // 设置画布的宽高, 整个浏览器为画布的宽高，-6 是为了去除边框
    main.style.position = "absolute";
    main.style.left = "3px";
    main.style.top = '3px';
    main.width = window.innerWidth - 6;
    main.height = window.innerHeight - 6;
    // TODO 初始化建筑

    // 初始化学生数组
    for (let i = 1; i <= initData.studentLength; i++) {
        let x = utils.random(initData.r + initData.frameWidth, main.width - initData.r - initData.frameWidth);
        let y = utils.random(initData.r + initData.frameWidth, main.height - initData.r - initData.frameWidth);
        let speedX = utils.random(-50, 60);      // 学生的x轴速度
        let speedY = utils.random(-50, 60);      // 学生的y轴速度
        let healthStatus = utils.randomOne(initData.healthStatus.data); // 随机产生学生的健康状态
        let facialMask = utils.randomOne(initData.facialMask.data); // 随机产生学生的是否佩戴口罩
        let monitor = utils.randomOne(initData.monitor.data); // 随机产生学生的核算监测结果
        let position = new StudentPosition(
            x,
            y,
            initData.r,
            initData.frameWidth,
            initData.facialMask[facialMask],
            initData.healthStatus[healthStatus],
            initData.monitor[monitor]
        );
        // id,health,isMask,isVirus,result,isStop,position,initSpeedX,initSpeedY
        let student = new Student(
            i + '',
            healthStatus,   // 健康
            facialMask,
            false,
            monitor,
            false,
            position,
            speedX,
            speedY
        );
        initData.students.push(student);
    }
    // console.log(initData.students);
    // 创建帧对象
    initData.frame = new Frame(context, initData, main.width, main.height,);
}

// 当浏览器窗口改变时，改变canvas的大小

// 模拟时间 单位：h
// 上一帧的时间
let date = new Date();
loop(); // 模拟系统运行
// initData.frame.render();

// initData.students.forEach(student=>{
//     collisionStudent(student);
//
// })

function loop() {
    context.save();
    // 这部分用于得出这一帧距离上一帧的时间差（真实时间）
    let now = new Date();
    let dt = now - date;
    initData.time += dt / 1000;
    date = now;

    //  这部分用于将系统时间转换为模拟时间对应的小时和天数
    let show_Time = initData.time * initData.timeShift;
    let day = Math.floor(show_Time / 24);
    initData.hour = Math.floor(show_Time % 24);
    // 当天数改变（过来一天），对学生的信息状态进行操作
    if (day !== initData.day) {
        initData.day = day;
        //TODO  天数改变的时候，执行的门户函数，函数中包含了对学生数据的检测（因为学生的健康数据需要每天做次检测，核算检测也是隔几天做一次的）
        dayChange();
    }
    // 检测是否发放核酸结果
    nucleicAcidRelease();
    // 渲染
    initData.frame.render();
    // 对学生的行为进行检测
    initData.students.forEach(student => {
        // 判断学生是否超出画布（学校）
        monitoringCrossBorder(student, 0, 0, main.width, main.height);
        // TODO 判断学生是否超过学校的建筑
        // TODO 判断学生是否越多学校的建筑
        // 学生移动
        studentMove(student, dt);
        // 判断学生是否接触
        collisionStudent(student);
        // console.log(student.id+'的患病率为：'+student.prevalence);
    });
    // 当浏览器改变时，改变canvas的大小
    window.onresize = function () {
        init();
    }
    context.restore();
    window.requestAnimationFrame(loop);
}


// 学生运动
function studentMove(student, dt) {
    // console.log(student);
    // 学生移动
    student.position.x += (student.speed.x * (dt / 1000));
    student.position.y += (student.speed.y * (dt / 1000));
    // 添加噪声
    let noise = utils.noise(
        student.position.x,
        student.position.y,
        -initData.noiseAmplitude,
        initData.noiseAmplitude
    );
    student.position.x = noise.x;
    student.position.y = noise.y;
    // 更新学生的存活时间
    let surviveTime = initData.time * initData.timeShift;
    student.day = Math.floor(surviveTime / 24);
    student.hour = Math.floor(surviveTime % 24);
    // console.log(noise);
    // console.log(student.day,student.hour);
    // console.log(student.position.x,student.position.y);
}

// 监测学生是否越界，越界，速度相反，折返
function monitoringCrossBorder(student, beginX, beginY, w, h) {
    if (
        ((student.position.x - student.position.lineWidth - student.position.r) <= beginX)
        ||
        ((student.position.x + student.position.r + student.position.lineWidth) >= (beginX + w))
    ) {
        // 将物体放置到边界内, 防止噪声，使速度的方向不变
        if ((student.position.x - student.position.lineWidth - student.position.r) <= beginX) {
            student.position.x = student.position.r + student.position.lineWidth + beginX;
        }
        if ((student.position.x + student.position.r + student.position.lineWidth) >= (beginX + w)) {
            student.position.x = beginX + w - student.position.r - student.position.lineWidth;
        }
        student.speed.x = -student.speed.x;
        // console.log('x轴超出边界');
    }
    if ((student.position.y - student.position.lineWidth - student.position.r) <= beginY
        ||
        ((student.position.y + student.position.r + student.position.lineWidth) >= beginY + h)
    ) {
        // 将物体放置到边界内, 防止噪声，使速度的方向不变
        if ((student.position.y - student.position.lineWidth - student.position.r) <= beginY) {
            student.position.y = student.position.r + student.position.lineWidth + beginY;
        }
        if ((student.position.y + student.position.r + student.position.lineWidth) >= (beginY + h)) {
            student.position.y = beginY + h - student.position.r - student.position.lineWidth;
        }
        student.speed.y = -student.speed.y;
        // console.log('y轴超出边界');
    }
}

// TODO 检验建筑内部碰撞
// 思路：根据中心点到两边的距离
function internalCollision(student, centerX, centerY, w, h) {

}

// TODO 监测建筑外的碰撞
function collisionOut(student, centerX, centerY, w, h) {
    let beginX = centerX - w / 2;
    let beginY = centerY - h / 2;
    let endX = centerX + w / 2;
    let endY = centerY + h / 2;
    if (
        student.position.x + student.position.r >= beginX
        && student.position.x - student.position.r <= endX
        && student.position.y + student.position.r >= beginY
        && student.position.y - student.position.r <= endY) {
        student.speed.x = -student.speed.x;
        // student.speed.y = -student.speed.y;
        student.position.x -= initData.noiseAmplitude;
    }
}

// TODO 监测学生与学生之间是否接触
function collisionStudent(student) {
    initData.students.forEach(s => {
        if (s.id !== student.id) {
            // 两球之间距离小于半径之和
            let distance = utils.distance(student.position.x, student.position.y, s.position.x, s.position.y);
            if (distance <= student.position.r + s.position.r) {
                // 监测
                healthStatus(student, s);
                // console.log(s.id +"的患病率:"+s.prevalence);
            }
        }
    })
}

// 检测学生的健康状态, 不会改变学生的健康状态（改变学生的患病概率），根据学生的患病概率进行改变
function healthStatus(monitor, detected) {
    // 被检测者不健康
    if (monitor.health === 'health' && detected.health !== 'health') {
        if (!monitor.isVirus) {   // 接触者没有携带病毒
            // 检测者未携带病毒
            monitor.isVirus = true; // 检测者携带病毒
        }
        // 概率累加
        // 根据接触的状况进行概率相加
        monitor.prevalence += initData.probability[detected.health + 'Probability'];
        // 根剧接触者是否佩戴口罩，对患病率进行相加（注意：佩戴口罩的额外患病概率为-10，不佩戴口罩的额外患病概率为0）
        monitor.prevalence += initData.probability[detected.isMask + 'Probability'];
        // 根据自身是否佩戴口罩，对患病率进行相加
        monitor.prevalence += initData.probability[monitor.isMask + 'Probability'];
        //console.log('接触者'+monitor.id+"的患病率为："+monitor.prevalence);
    }
}

// TODO 当天数改变时，执行的函数, 每天执行一次
function dayChange() {
    // 当天数改变时，判断是否做核酸，并记录每位学生核酸的时间,等到核酸出接口时，对学生的状态进行改变
    if (initData.nucleicAcid.whetherNucleicAcid){
        // 做核酸
        if (initData.day !== 0 && initData.day % initData.nucleicAcid.nucleicAcidSpacers === 0){
            // 到了做核酸的日期了,为全体学生做核酸检测
            initData.nucleicAcid.isNucleicAcidNow = true;   // 开启做核酸的信号
            // 记录本次核酸的时间
            initData.nucleicAcid.day = initData.day;
            initData.nucleicAcid.hour = initData.hour;
            // 更新核酸是否发放的状态
            initData.nucleicAcid.isTheResultReleased = false;
            console.log('开始全员核酸');
        }
    }
    // 因为每个检测程序都需要遍历一遍学生列表
    initData.students.forEach(student => {
        // 核酸检测
        nucleicAcidAmplificationTesting(student);
        // 学生是否患病检测  每天一次检测
        detectDisease(student);

    });

    // 一天结束，如果今天做了核酸，将现在是否在做核酸关闭
    if (initData.nucleicAcid.isNucleicAcidNow){
        initData.nucleicAcid.isNucleicAcidNow = false;
    }
}

// 每天检测一次，对患病的人进行患病操纵
function detectDisease(student) {
    // 检测
    if (student.isVirus && student.health === 'health') {
        // 学生携带病毒，并且健康状况为健康
        // 根据学生自身的患病概率进行患病操作
        console.log('检测' + student.id + "， 其患病概率为：" + student.prevalence);
        if (probability(student.prevalence)) {
            // 确定患病
            if (probability(initData.symptom)) {
                // 感染，并有症状（发病患者）
                student.health = initData.healthStatus.data[2];    // 健康状态改为发病
                // 将学生显示的填充颜色变为对应的患病时的颜色
                student.position.fillColor = initData.healthStatus[student.health + 'Probability'];
                console.log(student.id + "发病")
            } else {
                // 感染，但没有症状(无症状患者)
                student.health = initData.healthStatus.data[1];
                // 将学生的显示的填充颜色变为对应的无症状患病时的颜色
                //console.log(initData.healthStatus[student.health])
                student.position.fillColor = initData.healthStatus[student.health];
                // console.log(student.id + student.health + "填充颜色为：" + student.position.fillColor);
            }
        }
    }

}

// 核算检测
function nucleicAcidAmplificationTesting(student) {
    if (initData.nucleicAcid.isNucleicAcidNow){
        // 现在全体核酸，对该学生进行核酸检测
        if (student.isVirus){
            // 携带病毒，核酸阳性
            // 已做核酸
            student.makeNucleicAcid.whetherNucleicAcid = true;
            student.makeNucleicAcid.result = 'masculine';   // 核酸结果为阳性，暂存在核酸中，用作延迟发放
        }else {
            // 为携带病毒，核酸为阴性
            student.makeNucleicAcid.whetherNucleicAcid = true;
            student.makeNucleicAcid.result = 'negative';
        }
    }
}

// TODO 核酸结果发放
function nucleicAcidRelease(){
    // 判断系统是否开启了做核酸
    if (initData.nucleicAcid.whetherNucleicAcid){
        // 系统开启了做核酸，判断现在是否在做核酸,并判断是否发放了核酸结果
        if (!initData.nucleicAcid.isNucleicAcidNow && !initData.nucleicAcid.isTheResultReleased){
            // 现在系统没有在做核酸，判断核酸发放时间是不是到了
            let day_poor = initData.day - initData.nucleicAcid.day;// (天数差肯定会大于等于0)
            let hour_poor = initData.hour - initData.nucleicAcid.hour;  // (小时差)
            let poor = day_poor * 24 + hour_poor;
            if (poor >= initData.nucleicAcid.nucleicAcidResults){
                // 到了发放核酸的时间了
                initData.students.forEach(student=>{
                    if (student.makeNucleicAcid.result !== ''){
                        student.makeNucleicAcid.whetherNucleicAcid = false;      // 学生
                        student.result = student.makeNucleicAcid.result;
                        // 改变要实现学生的数据
                        student.position.textColor = initData.monitor[student.result];
                        console.log('发放核酸结果：学生'+student.id+"的核酸结果为："+student.result+"应渲染的字体颜色为："+student.position.textColor);
                    }
                });
                initData.nucleicAcid.isTheResultReleased = true;
            }
        }
    }
}



